﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

//c++前言

//1. 什么是C++ 
//C语言是结构化和模块化的语言，适合处理较小规模的程序。对于复杂的问题，规模较大的程序，需要高度
//的抽象和建模时，C语言则不合适。为了解决软件危机， 20世纪80年代， 计算机界提出了OOP(object
//oriented programming：面向对象)思想，支持面向对象的程序设计语言应运而生。
//1982年，Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念，发明了一种新的程序语
//言。为了表达该语言与C语言的渊源关系，命名为C++。因此：C++是基于C语言而产生的，它既可以进行C语
//言的过程化程序设计，又可以进行以抽象数据类型为特点的基于对象的程序设计，还可以进行面向对象的程
//序设计。


//2.C++的发展史 
//1979年，贝尔实验室的本贾尼等人试图分析unix内核的时候，试图将内核模块化，于是在C语言的基础上进
//行扩展，增加了类的机制，完成了一个可以运行的预处理程序，称之为C with classes


//c++兼容c语言，所以c++的编译下也可以用c
int main()
{
	printf("hello bit\n");


	return 0;
}

//阶段                                                                内容
//C withclasses              类及派生类、公有和私有成员、类的构造和析构、友元、内联函数、赋值运算符重载等
//C++1.0                                       添加虚函数概念，函数和运算符重载，引用、常量等
//C++2.0           更加完善支持面向对象，新增保护成员、多重继承、对象的初始化、抽象类、静态成员以及const成员函数
//C++3.0                            进一步完善，引入模板，解决多重继承产生的二义性问题和相应构造和析构的处理
//C++98           C++标准第一个版本，绝大多数编译器都支持，得到了国际标准化组织(ISO)和美国标准化协会认可，以模板方式重写C++标准库，引入了STL(标准模板库)
//C++03                            C++标准第二个版本，语言特性无大改变，主要：修订错误、减少多异性
//C++05     C++标准委员会发布了一份计数报告(Technical Report，TR1)，正式更名C++0x，即：计划在本世纪第一个10年的某个时间发布
//C++11    增加了许多特性，使得C++更像一种新语言，比如：正则表达式、基于范围for循环、auto关键字、新容器、列表初始化、标准线程库等
//C++14    对C++11的扩展，主要是修复C++11中漏洞以及改进，比如：泛型的lambda表达式，auto的返回值类型推导，二进制字面常量等
//C++17      在C++11上做了一些小幅改进，增加了19个新特性，比如：static_assert()的文本信息可选，Fold表达式用于可变的模板，if和switch语句中的初始化器等
//C++20      自C++11以来最大的发行版，引入了许多新的特性，比如：模块(Modules)、协程(Coroutines)、范围(Ranges)、概念(Constraints)等重大特性，还有对已有特性的更新：比如Lambda支持模板、范围for支持初始化等
//C++23                                                               制定ing


//3.c++入门
//1. C++关键字(C++98) 
//C++总计63个关键字，C语言32个关键字
//ps：下面我们只是看一下C++有多少关键字，不对关键字进行具体的讲解。后面我们学到以后再
//细讲。

//asm do if return try continue
//auto double inline short typedef for
//bool dynamic_cast int signed typeid public
//break else long sizeof typename throw
//case enum mutable static union wchar_t
//catch  explicit  namespace  static_cast  unsigned  default
//char  export  new  struct  using  friend
//class  extern  operator  switch  virtual  register
//const false private  template void true
//const_cast  ﬂoat  protected  this  volatile  while
//delete   goto  reinterpret_cast


//4.命名空间 
//在C / C++中，变量、函数和后面要学到的类都是大量存在的，这些变量、函数和类的名称将都存
//在于全局作用域中，可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化，
//以避免命名冲突或名字污染，namespace关键字的出现就是针对这种问题的。

 
#include <stdlib.h>
int rand = 10;
// C语言没办法解决类似这样的命名冲突问题，所以C++提出了namespace来解决
int main()
{
	printf("%d\n", rand);
	return 0;
}
// 编译后后报错：error C2365: “rand”: 重定义；以前的定义是“函数”
//因为其与<stdlib.h>中的库函数中rand冲突

//上述问题用一个关键字namespace解决
//namespace-----命名空间，解决命名冲突用

//4.1 命名空间定义 
//定义命名空间，需要使用到namespace关键字，后面跟命名空间的名字，然后接一对{}即可，{}
//中即为命名空间的成员

//用namespace的定义的域来解决
//域分为类域，命名空间域，局部域和全局域
//在C++中，想要访问全局的变量，就可以使用（::域作用限定域）

int a;
int main()
{
	int a = 0;

	//::使用域局部限定域
	printf("%d\n", ::a);//访问全局域
}

//局部与、命名空间与、全局域的访问顺序
int a = 0;
namespace tjp
{
	int a = 10;
}
//默认i情况下：
//局部域 -> 全局域 -> 展开命名空间域  or  指定访问命名空间域

//展开命名空间的方法：(这里的展开是指编译时，是否去命名空间搜索）
using namespace tjp;//展开命名空间
int main()
{
	int a = 9;
	printf("%d\n", a);
}

// bit是命名空间的名字，一般开发中是用项目名字做命名空间名。
// 1. 正常的命名空间定义
namespace tjp
{
	// 命名空间中可以定义变量/函数/类型
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}//此处不能给分号
//2. 命名空间可以嵌套
// test.cpp
namespace N1
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}
	namespace N2
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}

//此处的N2的变量如何访问呢?
int main()
{
	printf("%d\n", N1::N2::d);//在N2中访问d
	return 0;
}

//3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
// ps：一个工程中的test.h和上面test.cpp中两个N1会被合并成一个
// test.h
namespace N1
{
	int Mul(int left, int right)
	{
		return left * right;
	}
}

//注意：
//1.一个命名空间就定义了一个新的作用域，命名空间中的所有内容都局限于该命名空间中
//2.在命名空间结束的末尾括号不能给分号

#include<iostream>
//std是C++标准库的命名空间名，C++将标准库的定义实现都放到这个命名空间中
using namespace std;//必须使用这个语句将c++中的std命名空间给展开才可以使用库中的c++库和stl
//但是这里直接展开会有风险，如果与库里面的命名重复就会报错
//项目里不要直接展开，项目中建议指定访问，不要轻易展开命名空间

//如果太多，就可以使用using直接将常用的展开
using std::cout;
using std::endl;
int main()
{
	cout << "Hello world!!!" << endl;
	//或者直接指定访问
	std::cout << "hello bit" << std::endl;
	//如果太多，就可以使用using直接将常用的展开
	cout << "Hello world!!!" << endl;
	cout << "Hello world!!!" << endl;
	cout << "Hello world!!!" << endl;
	cout << "Hello world!!!" << endl;
	return 0;
}

//4.2 命名空间使用 
//命名空间中成员该如何使用呢？比如：
namespace Add
{
	// 命名空间中可以定义变量/函数/类型
	int a = 0;
	int b = 1;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}
int main()
{
	// 编译报错：error C2065: “a”: 未声明的标识符
	printf("%d\n", a);
	return 0;
}


//命名空间的使用有三种方式：
//（1）加命名空间名称及作用域限定符（指定访问）
int main()
{
	printf("%d\n", N::a);
	return 0;
}
//（2）使用using将命名空间中某个成员引入（展开部分）
using N::b;//把N中的b展开
int main()
{
	printf("%d\n", N::a);
	printf("%d\n", b);
	return 0;
}
//（3）使用using namespace直接将其全部展开（有风险）
using namespace N;
int main()
{
	printf("%d\n", b);
	Add(10, 20);
	return 0;
}

//那么现在解决开头的rand命名冲突的问题就很简单了
namespace rand
{
	int rand = 90;
}
int main()
{
	printf("%d\n",rand::rand);//通过访问命名空间域来进行访问rand全局变量
}


//5.C++输入和输出 
//新生婴儿会以自己独特的方式向这个崭新的世界打招呼，C++刚出来后，也算是一个新事物，
#include<iostream>//(io头文件)
// std是C++标准库的命名空间名，C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
	cout << "Hello world!!!" << endl;
	//cout可以自动识别类型
	int x = 0;
	float y = 1.1;
	cout << x << " " << y << endl;
	return 0;
}

//说明：
//1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时，必须包含< iostream >头文件
//以及按命名空间使用方法使用std。
//2. cout和cin是全局的流对象，endl是特殊的C++符号，表示换行输出换行，他们都包含在包含<iostream >头文件中。
//3. << 是流插入运算符， >> 是流提取运算符。
//4. 使用C++输入输出更方便，不需要像printf / scanf输入输出时那样，需要手动控制格式。
//C++的输入输出可以自动识别变量类型。
//5. 实际上cout和cin分别是ostream和istream类型的对象， >> 和 << 也涉及运算符重载等知识，
//这些知识我们我们后续才会学习，所以我们这里只是简单学习他们的使用。后面我们还有有
//一个章节更深入的学习IO流用法及原理。
//注意：早期标准库将所有功能在全局域中实现，声明在.h后缀的头文件中，使用时只需包含对应
//头文件即可，后来将其实现在std命名空间下，为了和C头文件区分，也为了正确使用命名空间，
//规定C++头文件不带.h；旧编译器(vc 6.0)中还支持<iostream.h>格式，后续编译器已不支持，因
//此推荐使用<iostream>+std的方式

int main()
{
	int a;
	double b;
	char c;

	// 可以自动识别变量的类型
	std::cin >> a;//>>叫流提取运算符
	std::cin >> b >> c;

	std::cout << a << std::endl;
	std::cout << b << " " << c << std::endl;
	return 0;
}

//std命名空间的使用惯例： 
//std是C++标准库的命名空间，如何展开std使用更合理呢？
//1. 在日常练习中，建议直接using namespace std即可，这样就很方便。
//2. using namespace std展开，标准库就全部暴露出来了，如果我们定义跟库重名的类型 / 对
//象 / 函数，就存在冲突问题。该问题在日常练习中很少出现，但是项目开发中代码较多、规模
//大，就很容易出现。所以建议在项目开发中使用，像std::cout这样使用时指定命名空间 +
//using std::cout展开常用的库对象 / 类型等方式。